package com.fausto.learnimprint.security

import com.fausto.learnimprint.common.constant.JwtConstant
import com.fausto.learnimprint.utils.JwtUtil
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.authority.SimpleGrantedAuthority
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.core.userdetails.UsernameNotFoundException
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter
import org.springframework.stereotype.Component
import javax.servlet.FilterChain
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse

@Component
class JwtTokenFilter(
    authenticationManager: AuthenticationManager
) : BasicAuthenticationFilter(authenticationManager) {

    @Autowired
    private lateinit var jwtUtil: JwtUtil

    override fun doFilterInternal(
        request: HttpServletRequest,
        response: HttpServletResponse,
        filterChain: FilterChain
    ) {
        //是否为游客
        var isGuest = false
        //获取HTTP头中携带token的字段
        request.getHeader(JwtConstant.HEADER)?.let {
            //合法前缀
            if (it.startsWith(JwtConstant.PREFIX)) {
                //获取token
                val token = it.substring(JwtConstant.PREFIX.length)
                try {
                    //从token中获取用户信息
                    val userDetails = jwtUtil.loadUserByToken(token)
                    //是否已经有凭据信息保存
                    if (null == SecurityContextHolder.getContext().authentication) {
                        //没有则生成并保存
                        SecurityContextHolder.getContext().authentication =
                            UsernamePasswordAuthenticationToken(
                                userDetails,
                                null,
                                userDetails.authorities
                            ).apply {
                                //存储该请求中的其他身份验证的相关信息
                                details = WebAuthenticationDetailsSource().buildDetails(request)
                            }
                    }
                } catch (e: UsernameNotFoundException) {
                    //token中存储的用户信息有误或者token过期, 给予游客身份
                    isGuest = true
                }
            }
            //没有token, 是游客
        } ?: Unit.apply {
            isGuest = true
        }
        //以游客身份登陆
        if (isGuest) {
            //生成游客身份
            val user = com.fausto.learnimprint.core.model.entity.User(
                "GUEST",
                "GUEST",
                listOf(SimpleGrantedAuthority("GUEST"))
            )
            //保存该凭据
            SecurityContextHolder.getContext().authentication =
                UsernamePasswordAuthenticationToken(
                    user,
                    null,
                    user.authorities
                )
        }

        //放行该请求
        filterChain.doFilter(request, response)
    }
}